package com.jgraves.WikiToSpeech;
/*
 * Copyright (C) 2011 John Graves
 */

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.MalformedURLException;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Stack;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.ByteArrayBuffer;

import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.speech.tts.TextToSpeech;
import android.speech.tts.TextToSpeech.OnUtteranceCompletedListener;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnKeyListener;
import android.view.View.OnLongClickListener;
import android.webkit.WebView;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;

import com.jgraves.WikiToSpeech.objects.Answer;
import com.jgraves.WikiToSpeech.objects.Dictionary;
import com.jgraves.WikiToSpeech.objects.DictionaryEntry;
import com.jgraves.WikiToSpeech.objects.Question;
import com.jgraves.WikiToSpeech.objects.Rule;

// TODO Have alternative (faster) pull of JSON scripts into faster Java structure
// TODO Fade in text animations
// TODO h for help (both command and menu)
// TODO on-line documentation
// TODO Sort out way for playback language to be specified across Mac/Android

/**
 * Parses files or URLs into scripts which play using text-to-speech 
 * @author johngraves
 */
public class QuestionView extends Activity {

	// Define underscore as function to fetch string resources
	private String _(Integer resourceId) {
		return this.getResources().getString(resourceId);
	}

	private String fileOrURLToOpen;

	private TextToSpeech mTts;

	// Preferences
	private boolean mSilentMode;

	// Identifiers for menu items
	private static final int OPEN_MENU_ID = Menu.FIRST;
	private static final int SETTINGS_MENU_ID = Menu.FIRST+1;
	private static final int EXIT_MENU_ID = Menu.FIRST+2;
	private static final int CONTENTS_MENU_ID = Menu.FIRST+3;
	private static final int INPUT_MENU_ID = Menu.FIRST+4;
	private static final int BARCODE_MENU_ID = Menu.FIRST+5;

	/** The file name or URL on the response side of an answer;[destination]response 
	 * or provided by an open command
	 * */
	private String mDestination;

	/** Data source for sequence */
	private InputStream instream;
	/** Flag for type of data source 
	 * <ul><li>HTML (0)
	 * <li>TXT (1)</ul>
	 */
	/** Required for HTTP access to web based scripts */
	private HttpResponse mHttpResponse;
	/** Required to buffer HTTP access to web based scripts */
	private BufferedReader mBufferedReader;

	private History mHistory;

	/** List of strings to build sequence from scratch */
	private List<String> mStrings;

	// Next advance
	private String mUtteranceID;

	// Layouts
	private LinearLayout mTTSLinearLayout;

	private TextView mLineTextView;
	private TextView mAnswerTextView0;
	private TextView mAnswerTextView1;
	private TextView mAnswerTextView2;
	private TextView mAnswerTextView3;
	private TextView mAnswerTextView4;
	private TextView mAnswerTextView5;
	private ArrayList<TextView> mAnswerTextViewList = new ArrayList<TextView>();
	private EditText mInputEditText;
	private LinearLayout mFlashcardLinearlayout;
	private Button mHardestButton;
	private Button mHardButton;
	private Button mGoodButton;
	private Button mEasyButton;
	private LinearLayout mLoadingLayout;
	private LinearLayout mImageLayout;
	private ImageView mImageImageView;
	private WebView mWebView;

	/** Button to retrace steps through question sequence 
	 * <p>Will step back into prior question sequence using database of question sequence history</p>
	 */
	private Button mBackButton;

	/** Button to reload and replay again the text-to-speech of current question
	 */
	private Button mRepeatButton;
	private Boolean mRepeatButtonPressed = false;

	private Intent intent;

	// Need handler for callbacks to the UI thread
	final Handler mHandler = new Handler();
	private Stack<String> mUtteranceStack = new Stack<String>();

	// Create runnable for posting
	final Runnable mNextAdvance = new Runnable() {
		public void run() {
			//print("Runnable run with mUtteranceStack status: "+ mUtteranceStack.isEmpty());
			if (mUtteranceStack.isEmpty()) {
				respondToOnClick(0);
			} else {
				SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
				mHandler.postDelayed(mNextAdvance, Integer.valueOf(prefs.getString("nextDelay", "2000"))); 
			}
		}
	};

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		mTts = WikiToSpeech.mTts;

		setContentView(R.layout.question_view);

		// Bind and setup view elements
		mLoadingLayout = (LinearLayout) findViewById(R.id.loading_linearlayout);

		mImageLayout = (LinearLayout) findViewById(R.id.image_linearlayout);
		mImageImageView = (ImageView) findViewById(R.id.image_imageview);
		mWebView = (WebView) findViewById(R.id.question_webview);
		mWebView.getSettings().setJavaScriptEnabled(true);

		mTTSLinearLayout = (LinearLayout) findViewById(R.id.tts_linearlayout);
		Integer backgroundColor = State.backgroundColor(getApplicationContext());
		if (null==backgroundColor){
			backgroundColor=getResources().getColor(R.color.WTSTeal);
		}
		mTTSLinearLayout.setBackgroundColor(backgroundColor);

		mLineTextView = (TextView) findViewById(R.id.line_textview);
		mLineTextView.setTextSize(Constants.TEXTSIZE);
		mLineTextView.setText(this.getResources().getString(R.string.wiki_to_speech) + this.getResources().getString(R.string.commands));

		mAnswerTextView0 = (TextView) findViewById(R.id.answer_text_view0);
		mAnswerTextView0.setVisibility(View.INVISIBLE);
		mAnswerTextView0.setTextSize(Constants.TEXTSIZE);
		mAnswerTextViewList.add(mAnswerTextView0);
		mAnswerTextView1 = (TextView) findViewById(R.id.answer_text_view1);
		mAnswerTextView1.setVisibility(View.GONE);
		mAnswerTextView1.setTextSize(Constants.TEXTSIZE);
		mAnswerTextViewList.add(mAnswerTextView1);
		mAnswerTextView2 = (TextView) findViewById(R.id.answer_text_view2);
		mAnswerTextView2.setVisibility(View.GONE);
		mAnswerTextView2.setTextSize(Constants.TEXTSIZE);
		mAnswerTextViewList.add(mAnswerTextView2);
		mAnswerTextView3 = (TextView) findViewById(R.id.answer_text_view3);
		mAnswerTextView3.setVisibility(View.GONE);
		mAnswerTextView3.setTextSize(Constants.TEXTSIZE);
		mAnswerTextViewList.add(mAnswerTextView3);
		mAnswerTextView4 = (TextView) findViewById(R.id.answer_text_view4);
		mAnswerTextView4.setVisibility(View.GONE);
		mAnswerTextView4.setTextSize(Constants.TEXTSIZE);
		mAnswerTextViewList.add(mAnswerTextView4);
		mAnswerTextView5 = (TextView) findViewById(R.id.answer_text_view5);
		mAnswerTextView5.setVisibility(View.GONE);
		mAnswerTextView5.setTextSize(Constants.TEXTSIZE);
		mAnswerTextViewList.add(mAnswerTextView5);

		mInputEditText = (EditText) findViewById(R.id.input_edittext);
		mInputEditText.setVisibility(View.GONE);

		mFlashcardLinearlayout = (LinearLayout) findViewById(R.id.flashcard_linearlayout);
		mFlashcardLinearlayout.setVisibility(View.GONE);
		mHardestButton = (Button) findViewById(R.id.hardest_button);
		mHardButton = (Button) findViewById(R.id.hard_button);
		mGoodButton = (Button) findViewById(R.id.good_button);
		mEasyButton = (Button) findViewById(R.id.easy_button);

		mBackButton = (Button) findViewById(R.id.back_button);
		mBackButton.setVisibility(View.GONE);
		mRepeatButton = (Button) findViewById(R.id.repeat_button);

		// Restore preferences
		SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
		mSilentMode = prefs.getBoolean("silentMode", false);
		State.setLanguage(prefs.getString("language", "UK"));

		// Greet the user.
		//		myList = readFileFromLocal(this);
		//		final String siteUrl = "http://code.google.com/p/open-allure-ds/wiki/Music";
		//final String siteUrl = "http://localhost:8000/music.html";
		//final String siteUrl = "http://127.0.0.1:8000/music.html";
		//		instream = QuestionView.this.getResources().openRawResource(R.raw.chatterboxchallenge2011script);
		// TODO				final String siteUrl = "http://openallure.wikia.com/wiki/Category:Open_Allure_Script";
		// TODO				final String siteUrl = "http://openallureds.ning.com/profiles/blogs/music-1";

		State.setOnQuestion(0);
		State.clearQuestionsVisited();

		mTTSLinearLayout.setOnLongClickListener(new OnLongClickListener() {

			public boolean onLongClick(View v) {
				mInputEditText.setVisibility(View.VISIBLE);
				return true;
			}
		});

		mInputEditText.setOnKeyListener(new OnKeyListener() {
			public boolean onKey(View v, int keyCode, KeyEvent event) {
				// If the event is a key-down event on the "enter" button
				if ((event.getAction() == KeyEvent.ACTION_DOWN) &&
						(keyCode == KeyEvent.KEYCODE_ENTER)) {
					// Perform action on key press
					String commandString = mInputEditText.getText().toString();
					print("commandString from  mInputEditText:" + commandString);
					parseCommandString(commandString);
					return true;
				}
				return false;
			}
		});

		mBackButton.setOnClickListener(new View.OnClickListener() {

			public void onClick(View v) {
				makeTTSStop();
				if (0<State.getOnQuestion() && null!=State.peekQuestionsVisited()) {
					// remove current question from stack
					while ((!State.getQuestionsVisited().empty()) && (State.peekQuestionsVisited()==State.getOnQuestion())) {
						State.popQuestionsVisited();
					}
					// fetch prior question from stack
					if (!State.getQuestionsVisited().empty()) {
						State.setOnQuestion(State.popQuestionsVisited());
					}
					// If onQuestion outside of sequence, goto question 0
					if (0>State.getOnQuestion() || State.getOnQuestion()>State.getSequence().getSize()-1) {
						State.setOnQuestion(0);
					}
					// If this returns to question 0, hide Back button
					if (0==State.getOnQuestion()) {
						mBackButton.setVisibility(View.GONE);
					}

					showQuestion();
				}
			}
		});

		mRepeatButton.setOnClickListener(new View.OnClickListener() {

			public void onClick(View v) {
				mRepeatButtonPressed = true;
				if (State.getOnQuestion() < State.getSequence().getSize()) {
					// remove current question from stack
					if (!State.getQuestionsVisited().empty()) {
						State.setOnQuestion(State.getQuestionsVisited().pop());
					}
					if (State.getSetOfQuestionsVisited().contains(State.getOnQuestion())) {
						State.getSetOfQuestionsVisited().remove(State.getOnQuestion());
					}

					makeTTSStop();

					showQuestion();
				}
			}
		});

		mHardestButton.setOnClickListener(new View.OnClickListener() {

			public void onClick(View v) {
				if (State.getOnQuestion() < State.getSequence().getSize()) {
					mFlashcardLinearlayout.setVisibility(View.GONE);
					State.setOnQuestion(State.getOnQuestion()+1);
					showQuestion();
				}
			}
		});

		mHardButton.setOnClickListener(new View.OnClickListener() {

			public void onClick(View v) {
				if (State.getOnQuestion() < State.getSequence().getSize()) {
					mFlashcardLinearlayout.setVisibility(View.GONE);
					State.setOnQuestion(State.getOnQuestion()+1);
					showQuestion();
				}
			}
		});

		mGoodButton.setOnClickListener(new View.OnClickListener() {

			public void onClick(View v) {
				if (State.getOnQuestion() < State.getSequence().getSize()) {
					mFlashcardLinearlayout.setVisibility(View.GONE);
					State.setOnQuestion(State.getOnQuestion()+1);
					showQuestion();
				}
			}
		});

		mEasyButton.setOnClickListener(new View.OnClickListener() {

			public void onClick(View v) {
				if (State.getOnQuestion() < State.getSequence().getSize()) {
					mFlashcardLinearlayout.setVisibility(View.GONE);
					State.setOnQuestion(State.getOnQuestion()+1);
					showQuestion();
				}
			}
		});

		mImageImageView.setOnClickListener(new View.OnClickListener() {

			public void onClick(View v) {
				respondToOnClick(0);
			}
		});

		int result = State.setLanguage(this, prefs.getString("language", "UK"));
		if (result == TextToSpeech.LANG_MISSING_DATA ||
				result == TextToSpeech.LANG_NOT_SUPPORTED) {
			// Language data is missing or the language is not supported.
			Log.e(Constants.LOGCAT_TAG, "Language is not available.");
		} else {
			// Check the documentation for other possible result codes.
			// For example, the language may be available for the locale,
			// but not for the specified country and variant.

			// The TTS engine has been successfully initialized.
			// Allow the user to press the button for the app to speak again.
			mRepeatButton.setEnabled(true);
			//				myList = readFileFromLocal(this);
		}

		mLoadingLayout.setVisibility(View.VISIBLE);

		State.clearQuestionsVisited();

		fileOrURLToOpen = getIntent().getStringExtra(Constants.EXTRA_INPUT_STRING);
		int mExtraInputType = getIntent().getIntExtra(Constants.EXTRA_INPUT_TYPE,-1);
		State.setSequenceSourceType(mExtraInputType);

		// Check and update history
		mHistory = new History(this);
		List<String> inHistory = mHistory.selectAll();
		Boolean alreadyThere = false;
		for(String item:inHistory){
			if(item.equals(fileOrURLToOpen)){
				alreadyThere=true;
			}
		}
		if (!alreadyThere) {
			mHistory.insert(fileOrURLToOpen);
		}

		// Sort out appropriate action based on extras
		switch (State.getSequenceSourceType()) {
		case Constants.HTML_ETHERPAD:
			// Open Etherpad
			new OpenFileOrURLAsyncTask().execute();
			break;
		case Constants.HTML:
			// Open Wiki
			new OpenFileOrURLAsyncTask().execute();
			break;
		case Constants.TXT:
			if (null!=fileOrURLToOpen) {
				// Open local text file
				print(fileOrURLToOpen);
				//TODO - FIX
				if (fileOrURLToOpen != "/sdcard/WikiToSpeech/") {
					// Get rid of URI prefix:
					if (fileOrURLToOpen.startsWith("file://")) {
						fileOrURLToOpen = fileOrURLToOpen.substring(7);
					}
				}
				try {
					instream = new FileInputStream(fileOrURLToOpen);
				} catch (FileNotFoundException e) {
					e.printStackTrace();
				}
				ReadURL.readURL(this, instream, State.getDestinationType(fileOrURLToOpen));
				State.setOnQuestion(0);
				showQuestion();
			}
			break;
		case Constants.ZIP:
			if (null!=fileOrURLToOpen) {
				ZipFile zipFile;
				try {
					zipFile = new ZipFile(fileOrURLToOpen);
					ZipEntry scriptFile = zipFile.getEntry("script.txt");
					instream = zipFile.getInputStream(scriptFile);
				} catch (IOException e) {
					e.printStackTrace();
				}

				ReadURL.readURL(this, instream, Constants.ZIP);
				State.setOnQuestion(0);
				showQuestion();
			}
			break;
		case Constants.ZIP_HTTP:
			if (null!=fileOrURLToOpen) {
				new fetchZipFileAsyncTask().execute();
			}
			break;
		};

	} // end onCreate

	@Override
	protected void onResume(){		
		super.onResume();

	} // end onResume

	@Override
	protected void onStop(){
		super.onStop();

		Library.savePreferences(this);
	} // end onStop

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		super.onCreateOptionsMenu(menu);

		menu.add(0, OPEN_MENU_ID, 0, R.string.open)
		.setIcon(android.R.drawable.ic_menu_save);
		menu.add(0, EXIT_MENU_ID, 0, R.string.exit)
		.setIcon(android.R.drawable.ic_menu_revert);
		menu.add(0, INPUT_MENU_ID, 0, R.string.input)
		.setIcon(android.R.drawable.ic_menu_edit);
		menu.add(0, CONTENTS_MENU_ID, 0, R.string.contents)
		.setIcon(android.R.drawable.ic_menu_search);
		menu.add(0, SETTINGS_MENU_ID, 0, R.string.settings)
		.setIcon(android.R.drawable.ic_menu_preferences);
		menu.add(0, BARCODE_MENU_ID, 0, R.string.scan)
		.setIcon(android.R.drawable.ic_menu_preferences);
		return true;
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		makeTTSStop();
		// Handle all of the possible menu actions.
		switch (item.getItemId()) {
		case OPEN_MENU_ID:
			openFileDialog();
			break;
		case SETTINGS_MENU_ID:
			Intent launchPreferencesIntent = new Intent().setClass(this, Preferences.class);
			startActivityForResult(launchPreferencesIntent, Constants.REQUEST_CODE_PREFERENCES);
			break;
		case EXIT_MENU_ID:
			finish();
			break;
		case CONTENTS_MENU_ID:
			State.printSequence();
			Integer contentsFoundAt = State.getSequence().getmQuestionTagMap().get("contents");
			if (null!=contentsFoundAt) {
				State.setOnQuestion(contentsFoundAt);
				showQuestion();
			}
			break;
		case INPUT_MENU_ID:
			mInputEditText.setVisibility(View.VISIBLE);
			break;
		case BARCODE_MENU_ID:
			intent.setPackage("com.google.zxing.client.android");
			intent.putExtra("SCAN_MODE", "QR_CODE_MODE");
			startActivityForResult(intent, 0);

			break;
		}
		return super.onOptionsItemSelected(item);
	}

	private void makeTTSStop() {
		mHandler.removeCallbacks(mNextAdvance);
		Integer result = mTts.stop();
		if (-1==result) {
			// try again
			mTts.stop();
		}
		mUtteranceStack.clear();
	}

	// ------------------------
	public void showQuestion() {
		mLoadingLayout.setVisibility(View.GONE);
		mImageLayout.setVisibility(View.GONE);
		mRepeatButton.setText("Repeat");
		if (State.getLanguage().equals("IT")) {
			WikiToSpeech.setTTSLanguage(Locale.ITALIAN); 
		}

		// Start fresh with this question
		mUtteranceStack.clear();
		mHandler.removeCallbacks(mNextAdvance);

		// Check for change in language
		SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
		State.setLanguage(prefs.getString("language", "UK"));

		// Reveal Back button
		if (0<State.getOnQuestion() && !State.getQuestionsVisited().empty()) {
			mBackButton.setVisibility(View.VISIBLE);
		}

		// Add current question to stack if not already there
		if (!State.getQuestionsVisited().isEmpty()) {
			if (!State.peekQuestionsVisited().equals(State.getOnQuestion())) {
				State.pushQuestionVisited(State.getOnQuestion());
			}
		} else {
			State.pushQuestionVisited(State.getOnQuestion());
		}

		if (State.getOnQuestion() < State.getSequenceSize()) {

			// Change color with each question
			mTTSLinearLayout.setBackgroundColor(State.backgroundColor(getApplicationContext()));

			if(State.hideWebView()){
				mWebView.setVisibility(View.GONE);
			}

			// Show image (slide) if any
			if(""!=State.getQuestionLink()){
				// Show answer side link if any
				if (State.questionLinkIsImageFile()) {
					// fetch from SD Card 
					if (State.getQuestionLink().startsWith("/sdcard")) {
						mImageLayout.setVisibility(View.VISIBLE);
						mImageImageView.setImageURI(Uri.parse(State.getQuestionLink()));
					}
					// Fetch file from internet
					else if (State.getQuestionLink().startsWith("http")) {
						boolean success = false;
						int tries = 0;
						while (!success && tries<3){
							success = true;
							try {
								InputStream is = (InputStream) this.fetch(State.getQuestionLink());
								if(null!=is){
									Drawable d = Drawable.createFromStream(is, "src");
									mImageLayout.setVisibility(View.VISIBLE);
									mImageImageView.setImageDrawable(d);
								}
							} catch (MalformedURLException e) {
								e.printStackTrace();
								success = false;
							} catch (IOException e) {
								e.printStackTrace();
								success = false;
							}
							tries ++;
						}
					}
					// Fetch file from ZipFile
					else if (State.getSequenceSourceType()==Constants.ZIP) {
						// TODO
						ZipFile zipFile;
						if (null!=fileOrURLToOpen) {
							try {
								zipFile = new ZipFile(fileOrURLToOpen);
								ZipEntry imageFile = zipFile.getEntry(State.getQuestionLink());
								instream = zipFile.getInputStream(imageFile);
								Drawable d = Drawable.createFromStream(instream, "src");
								mImageLayout.setVisibility(View.VISIBLE);
								mImageImageView.setImageDrawable(d);
							} catch (IOException e) {
								e.printStackTrace();
							}

						}
					}
				} else {
					mWebView.setVisibility(View.VISIBLE);
					mWebView.loadUrl(State.getQuestionLink());
				}

			}

			// Say and display question part-by-part
			List<String> questionText = State.getQuestionText();

			// check, on the fly, whether to use dictionary

			String mLineText = "";
			for (String item : questionText) {
				// Look for any tokens marked by $ or ${xxx} and add them to the dictionary
				if(item.indexOf("$")>0){
					Pattern p = Pattern.compile("\\$\\{?(\\w*)[\\}\\s]?"); // {?(\\w*)[}\\s]
					Matcher m = p.matcher(item);
					while (m.find()) { // Find each match in turn
						String fullToken = m.group(0);
						String token = fullToken.replaceAll("[\\$\\{\\}]",""); 
						// Check if already in dictionary
						if (null==State.getDictionary()) {
							Dictionary dictionary = new Dictionary();
							State.setDictionary(dictionary);
						}
						if (State.getDictionary().contains(token)){
							String replacementText = State.getDictionary().getValueForToken(token);
							if (""!=replacementText) {
								item = item.replace(fullToken, replacementText);
								print(item);
							} else {
								// Need to ask question
								State.setNeedToken(token);
							}
						}
					} // finished making replacements
					if (State.getNeedToken()=="") {
						if (0==mLineText.length()) {
							mLineText = item + " ";
						} else {
							mLineText = mLineText + item + " ";
						}
						mLineTextView.setText(mLineText);
						if (null==State.getSetOfQuestionsVisited()) {
							//print("Saying: "+item);
							speak(item);
						} else if ((!State.getSetOfQuestionsVisited().contains(State.getOnQuestion()))||mRepeatButtonPressed) {
							//print("Saying: "+item);
							speak(item);
						}
						mRepeatButtonPressed = false;

					} else {
						mLineTextView.setText(State.getDictionary().getQuestionForToken(State.getNeedToken()));
						speak(State.getDictionary().getQuestionForToken(State.getNeedToken()));
					}
				} else {
					// show and say without replacements
					if (0==mLineText.length()) {
						mLineText = item + " ";
					} else {
						mLineText = mLineText + item + " ";
					}
					mLineTextView.setText(mLineText);
					if (null==State.getSetOfQuestionsVisited()) {
						//print("Saying: "+item);
						speak(item);
					} else if ((!State.getSetOfQuestionsVisited().contains(State.getOnQuestion()))||mRepeatButtonPressed) {
						//print("Saying: "+item);
						speak(item);
					}
				}
			}

			// Default to white text, hidden or gone text views for answers
			for (TextView tv : mAnswerTextViewList) {
				tv.setTextColor(getResources().getColor(R.color.WTSWhite));
				tv.setVisibility(View.GONE);
			}


			if(State.getNeedToken()=="") {
				// Say and display answers
				if (0<State.getAnswers().size() && "[flashcard]".equals(State.getFirstAnswerText())) {
					State.setFlashcardMode(true);
					mAnswerTextViewList.get(0).setText(_(R.string.flashcard));
					mAnswerTextViewList.get(0).setVisibility(View.VISIBLE);
				}
				else {
					State.setFlashcardMode(false);
					List<Answer> answers = State.getAnswers();
					Integer onAnswer = 0;
					for (Answer answer : answers) {
						if (!answer.isInput() && 0<answer.getAnswerText().length()) {
							mAnswerTextViewList.get(onAnswer).setText(answer.getAnswerText());
							mAnswerTextViewList.get(onAnswer).setVisibility(View.VISIBLE);
							// set color based on visited flag
							if (answer.isVisited()) {
								mAnswerTextViewList.get(onAnswer).setTextColor(getResources().getColor(R.color.WTSGray));
							} else {
								mAnswerTextViewList.get(onAnswer).setTextColor(getResources().getColor(R.color.WTSWhite));
							}
						}

						if (null==State.getSetOfQuestionsVisited()) {
							speak(answer.getAnswerText());
						} else if ((!State.getSetOfQuestionsVisited().contains(State.getOnQuestion()))||mRepeatButtonPressed) {
							speak(answer.getAnswerText());
						}

						// Setup to respond to answer selections
						switch (onAnswer) {
						case 0:
							mAnswerTextView0.setOnClickListener(new OnClickListener() {
								public void onClick(View v) {
									mAnswerTextView0.setTextColor(getResources().getColor(R.color.WTSGray));
									respondToOnClick(0);
								}
							});
							break;

						case 1:
							mAnswerTextView1.setOnClickListener(new OnClickListener() {
								public void onClick(View v) {
									mAnswerTextView1.setTextColor(getResources().getColor(R.color.WTSGray));
									respondToOnClick(1);
								}
							});
							break;

						case 2:
							mAnswerTextView2.setOnClickListener(new OnClickListener() {
								public void onClick(View v) {
									mAnswerTextView2.setTextColor(getResources().getColor(R.color.WTSGray));
									respondToOnClick(2);
								}
							});
							break;

						case 3:
							mAnswerTextView3.setOnClickListener(new OnClickListener() {
								public void onClick(View v) {
									mAnswerTextView3.setTextColor(getResources().getColor(R.color.WTSGray));
									respondToOnClick(3);
								}
							});
							break;

						case 4:
							mAnswerTextView4.setOnClickListener(new OnClickListener() {
								public void onClick(View v) {
									mAnswerTextView4.setTextColor(getResources().getColor(R.color.WTSGray));
									respondToOnClick(4);
								}
							});
							break;

						case 5:
							mAnswerTextView5.setOnClickListener(new OnClickListener() {
								public void onClick(View v) {
									mAnswerTextView5.setTextColor(getResources().getColor(R.color.WTSGray));
									respondToOnClick(5);
								}
							});
							break;
						}

						onAnswer += 1;
					}
				} 
				// Turn on input if any
				if (State.getQuestionHasInput()) {
					mInputEditText.setVisibility(View.VISIBLE);
					mImageLayout.setVisibility(View.GONE);
				} else {
					mInputEditText.setVisibility(View.GONE);
				}
			} else {
				// answer needToken question
				mInputEditText.setVisibility(View.VISIBLE);
			}

			if(null!=mTts) {
				mTts.setOnUtteranceCompletedListener(new OnUtteranceCompletedListener() {		
					public void onUtteranceCompleted(String utteranceId) {
						//print("Completed saying " + utteranceId);
						if(!mUtteranceStack.isEmpty()) {
							//print("Popping from stack");
							mUtteranceStack.pop();
						}
						if(!mUtteranceStack.isEmpty()) {
							print("On Utterance Stack "+mUtteranceStack.peek());
						}
					}
				});
			}
		} else {
			speak(_(R.string.you_have_reached_the_end));
			if(null!=mTts) {
				mTts.setOnUtteranceCompletedListener(new OnUtteranceCompletedListener() {		
					public void onUtteranceCompleted(String utteranceId) {
						finish();
					}
				});
			}
		}

		if(State.getNeedToken()=="") {
			// Add current question to set of visited questions
			State.addVisitedQuestion(State.getOnQuestion());
		}
	}


	@Override
	public void onDestroy() {
		// Don't forget to shutdown!
		mHandler.removeCallbacks(mNextAdvance);
		super.onDestroy();
	}


	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		super.onActivityResult(requestCode, resultCode, data);
		fileOrURLToOpen = "";
		switch (requestCode) {

		case 0:
			// Scan barcode
			if (resultCode == RESULT_OK) {
				String contents = data.getStringExtra("SCAN_RESULT");
				//				String format = data.getStringExtra("SCAN_RESULT_FORMAT");
				// Handle successful scan
				mInputEditText.setText(contents);
				mInputEditText.setVisibility(View.VISIBLE);
				// TODO
			} else if (resultCode == RESULT_CANCELED) {
				// Handle cancel
			}
			break;

		case Constants.REQUEST_CODE_PICK_FILE_OR_DIRECTORY:
			if(resultCode == RESULT_OK) {
				// Go to Question View with extras
				Intent i = new Intent(QuestionView.this, QuestionView.class);
				i.putExtra(Constants.EXTRA_INPUT_STRING, data.getStringExtra(Constants.EXTRA_FILENAME));
				i.putExtra(Constants.EXTRA_INPUT_TYPE, State.getDestinationType(data.getStringExtra(Constants.EXTRA_FILENAME)));
				i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
				startActivity(i);
			}
			break;
		}
		return;
	}

	// -----------------------
	public static void print(Object obj){
		System.out.println(obj.toString());
	}

	// ---------------------
	private void speak(String phrase) {
		if((null==mTts)||(""==phrase)||(0==phrase.length())){
			return;
		}
		SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
		mSilentMode = prefs.getBoolean("silentMode", false);
		print("Silent mode is: " + mSilentMode);
		phrase = phrase.trim();
		if (!mSilentMode && 
				!phrase.equals(State.getNextToken()) && 
				!phrase.equals(State.getInputToken()) && 
				!phrase.equals("[flashcard]") && 
				!phrase.endsWith("...")) {

			if (phrase.startsWith("[")) {
				if (phrase.endsWith("]")) {
					phrase = phrase.substring(1, phrase.length()-1);
				}
			}

			HashMap<String,String> mTtsTimeStampHashMap = new HashMap<String, String>();
			mUtteranceID = Long.toString(System.currentTimeMillis());
			print("Saying mUtteranceID of " + mUtteranceID);
			mTtsTimeStampHashMap.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, mUtteranceID);
			mTts.speak(phrase,
					TextToSpeech.QUEUE_ADD,  
					mTtsTimeStampHashMap);
			mUtteranceStack.push(mUtteranceID);
			print("Pushing to stack: "+ mUtteranceID);
		} 
		// This next line could be very confusing. The NextToken is [next] 
		// while the NeedToken is from a $name type of substitution
		if (phrase.equals(State.getNextToken()) && State.getNeedToken()=="") {
			mHandler.postDelayed(mNextAdvance, Integer.valueOf(prefs.getString("nextDelay", "2000")));
		}
	} // end speak()

	// ---------------------
	/** Determine how to handle command input
	 * <p>First look for commands
	 * <ul><li>e for exit
	 * <li>c for contents</ul>
	 * Then look for file names (with .txt) or URLS
	 * Then check against flashcard response
	 * Then look for command in tag list
	 * <p>Then look for command in full text
	 * <p>Parse stops when mSeekingNewQuestion = false
	 * @param commandString
	 */
	private void parseCommandString(String commandString) {
		if (0==commandString.length()) {
			return;
		}
		// Change background color to acknowledge start of parsing
		mTTSLinearLayout.setBackgroundColor(State.backgroundColor(getApplicationContext()));

		String commandStringLowerCase = commandString.toLowerCase().trim();
		print("commandString inside parse:" + commandStringLowerCase);

		if(State.getNeedToken()=="") {

			Boolean mSeekingNewQuestion = true;
			Integer onQuestionSearch = 0; // Counter for search
			Integer onQuestionFound = -1; // Holds result, -1 signals not found

			// Check script rules for match
			// For example, if commandString contains "Are you a bot?" and rule has compiled pattern of (are\s+you)\s+.*
			// then the ruletype, rulename and response should be returned
			Rule ruleMatched = new Rule();
			ruleMatched = RespondToCommand.respond(commandString,State.getRules());
			if (ruleMatched.getRuleType()=="") {
				// commandString did not match any rule

				// e for exit
				if (commandStringLowerCase.equals("e")) {
					finish();
				} // end of "e "

				// c for contents
				if (commandStringLowerCase.equals("c")) {
					State.printSequence();
					Integer contentsFoundAt = State.getSequence().getmQuestionTagMap().get("contents");
					if (null!=contentsFoundAt) {
						State.setOnQuestion(contentsFoundAt);
						mSeekingNewQuestion = false;
					}
				} // end of "c"

				// o for open
				if (mSeekingNewQuestion && commandStringLowerCase.equals("o")) {
					// select file to open with file manager asynchronously
					mSeekingNewQuestion = false;
					openFileDialog();
				} // end of "o " for open

				// http://<URL> opens scripts on the web after download to /sdcard/fromWeb.html
				// o <name> opens scripts on SD card
				if (mSeekingNewQuestion && (commandStringLowerCase.startsWith("http://")
						|| commandStringLowerCase.startsWith("https://"))) {
					fileOrURLToOpen = commandString;
					mSeekingNewQuestion = false;
					new OpenFileOrURLAsyncTask().execute();
				} // end http://

				// <name>.txt opens scripts on SD card
				if (mSeekingNewQuestion && 0<commandStringLowerCase.indexOf(".txt")) {
					fileOrURLToOpen = commandString;
					mSeekingNewQuestion = false;
					new OpenFileOrURLAsyncTask().execute();
				} // end .txt

				// silent mode
				if (commandStringLowerCase.equals("s+")) {
					speak("Switching to silent mode");
					mSilentMode = true;
					Library.savePreferences(this);
				} // end of "s+"
				if (commandStringLowerCase.equals("s-") && 2==commandStringLowerCase.length()) {
					mSilentMode = false;
					Library.savePreferences(this);
					speak("Switching out of silent mode");
				} // end of "s-"

				// Check flashcard response
				print("At command flashcard is: "+ State.isFlashcardMode());
				if (mSeekingNewQuestion &&  State.isFlashcardMode()) {
					flashcardResponse(commandStringLowerCase);
					mSeekingNewQuestion = false;
				}

				// Search for word in tags of sequence
				if (mSeekingNewQuestion) {
					if (null!=State.getSequence().getmQuestionTagMap() && State.getSequence().getmQuestionTagMap().containsKey(commandStringLowerCase)) {
						onQuestionFound = State.getSequence().getmQuestionTagMap().get(commandStringLowerCase);
						print("Found command at tag " + onQuestionFound);
						State.setOnQuestion(onQuestionFound);
						mSeekingNewQuestion = false;
					}
				} // end tag search

				// Search for word in full text of sequence
				if (mSeekingNewQuestion) {
					onQuestionSearch = 0; // Counter for search
					onQuestionFound = -1; // Holds result, -1 signals not found
					List<Question> questions = State.getQuestions();
					for (Question mQuestion : questions) {
						if (-1==onQuestionFound) {
							// Search the question texts for this question
							for (String mString : mQuestion.getQuestionTexts()) {
								if (-1<mString.toLowerCase().indexOf(commandStringLowerCase)) {
									onQuestionFound = onQuestionSearch;
									break;
								}
							}
							if (-1==onQuestionFound) {
								for (Answer mAnswer : mQuestion.getAnswers()) {
									// Search the answer text 
									if (-1<mAnswer.getAnswerText().toLowerCase().indexOf(commandStringLowerCase)) {
										onQuestionFound = onQuestionSearch;
										break;
									}
									// Search the response text
									if (-1<mAnswer.getResponseText().toLowerCase().indexOf(commandStringLowerCase)) {
										onQuestionFound = onQuestionSearch;
										break;
									}
								}
							}
							onQuestionSearch += 1;
						}
					}
					if (-1!=onQuestionFound) {
						print("Found command at " + onQuestionFound);
						State.setOnQuestion(onQuestionFound);
						mSeekingNewQuestion = false;
					}
				} // end full text search

			} else if ("_link".equals(ruleMatched.getRuleType())){
				// respond to matched rule
				if (null!=State.getSequence().getmQuestionTagMap() && 
						State.getSequence().getmQuestionTagMap().containsKey(ruleMatched.getRuleName())) {
					onQuestionFound = State.getSequence().getmQuestionTagMap().get(ruleMatched.getRuleName());
					print("Found match for rule name at tag " + onQuestionFound);
					State.setOnQuestion(onQuestionFound);
					mSeekingNewQuestion = false;
				}
				//TODO
			}
		} else {
			// store response in value of dictionary
			DictionaryEntry de = State.getDictionary().getEntryForToken(State.getNeedToken());
			de.setValue(commandString);
			State.getDictionary().updateEntry(de);
			State.setNeedToken("");
		}

		// clear command line
		mInputEditText.setText("");
		mInputEditText.setVisibility(View.INVISIBLE);

		showQuestion();	
	} // end parseCommandString()



	private void flashcardResponse(String s) {

		// Put response in answer and text view
		State.getSequence().getQuestion(State.getOnQuestion()).getAnswer(0).setAnswerText(State.getResponse(0));
		State.getSequence().getQuestion(State.getOnQuestion()).getAnswer(0).setInput(false);
		mAnswerTextView0.setText(State.getResponse(0));
		if (s.equals(State.getResponse(0).toLowerCase())) {
			speak("Correct");
		} else {
			speak(State.getResponse(0));
		}
		mInputEditText.setVisibility(View.GONE);
		mFlashcardLinearlayout.setVisibility(View.VISIBLE);

	}

	// ---------------------
	/** For selected answer, determine if there is a response and, if so, speak it.
	 * @param answer
	 */
	private void sayResponse(Integer answer) {
		if (""!=State.getResponse(answer)) {
			speak(State.getResponse(answer));
		}
	} // end sayResponse()



	// ---------------------
	/** response to selection of answer, including those with link or destination
	 * @param answer
	 */
	private void respondToOnClick(Integer answer) {
		State.setAnswerVisited(answer);
		makeTTSStop();
		if (State.isFlashcardMode()) {
			flashcardResponse(""); 
		} else {
			sayResponse(answer);
		}
		// Show answer side link if any
		if (""!=State.getLink(answer)) {
			if (State.linkIsImageFile(answer)) {
				// fetch from SD Card 
				if (State.getLink(answer).startsWith("/sdcard")) {
					mImageLayout.setVisibility(View.VISIBLE);
					mImageImageView.setImageURI(Uri.parse(State.getLink(answer)));
				}
				// Fetch file from internet
				else if (State.getLink(answer).startsWith("http")) {
					boolean success = false;
					int tries = 0;
					while (!success && tries<3){
						success = true;
						try {
							InputStream is = (InputStream) this.fetch(State.getLink(answer));
							if(null!=is){
								Drawable d = Drawable.createFromStream(is, "src");
								mImageLayout.setVisibility(View.VISIBLE);
								mImageImageView.setImageDrawable(d);
							}
						} catch (MalformedURLException e) {
							e.printStackTrace();
							success = false;
						} catch (IOException e) {
							e.printStackTrace();
							success = false;
						}
						tries ++;
					}
				}
			} else {
				mWebView.setVisibility(View.VISIBLE);
				mWebView.loadUrl(State.getLink(answer));
			}
		}
		// Follow destination if any
		if (""!=State.getDestination(answer)) {
			Intent i = new Intent(QuestionView.this, QuestionView.class);
			i.putExtra(Constants.EXTRA_INPUT_STRING, State.getDestination(answer));
			i.putExtra(Constants.EXTRA_INPUT_TYPE, State.getDestinationType(State.getDestination(answer)));
			i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
			startActivity(i);
		} else {
			if (!State.isFlashcardMode()) {
				State.advanceQuestion(answer);
			}
		}
		showQuestion();
	}

	public Object fetch(String address) throws MalformedURLException,IOException {
		try{
			URL url = new URL(address);
			Object content = url.getContent();
			return content;
		} catch (SocketTimeoutException e1) {
			e1.printStackTrace();
			speak("Sorry. The image could not be retrieved.");
			return null;
		} 
	}
	/**
	 * Opens the file manager to select a file to open.
	 */
	private void openFileDialog() {
		Intent intent = new Intent();
		intent.setClassName("com.jgraves.WikiToSpeech", "com.jgraves.WikiToSpeech.FileChooser");
		intent.putExtra(Constants.EXTRA_INPUT_TYPE, Constants.ZIP);
		startActivityForResult(intent, Constants.REQUEST_CODE_PICK_FILE_OR_DIRECTORY);
	}
    // --------------
	public void fetchZipFile() {

        URL url;
		try {
			url = new URL(fileOrURLToOpen);
			URLConnection ucon = url.openConnection();
			InputStream is = ucon.getInputStream();
			BufferedInputStream bis = new BufferedInputStream(is);
			ByteArrayBuffer baf = new ByteArrayBuffer(50);
			int current = 0;
			while ((current = bis.read()) != -1) {
				baf.append((byte) current);
			}
			// Prepare output file
			SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
			String mDirectoryPreference = prefs.getString("directory", getResources().getString(R.string.filepath));
		    int sep = fileOrURLToOpen.lastIndexOf("/");
			String fileName = fileOrURLToOpen.substring(sep + 1);
			File file = new File(mDirectoryPreference + "/" + fileName);
			// Write to output file
			FileOutputStream fos = new FileOutputStream(file);
			fos.write(baf.toByteArray());
			fos.close();
			
			fileOrURLToOpen = file.getAbsolutePath();
			State.setSequenceSourceType(State.getDestinationType(fileOrURLToOpen));
			
		} catch (MalformedURLException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}

	}
	// --------------
	public void openFileOrURL() {
		if (null!=fileOrURLToOpen && 0<fileOrURLToOpen.length()) {
			print(fileOrURLToOpen);
			if (fileOrURLToOpen.startsWith("http://") || fileOrURLToOpen.startsWith("https://")) {
				// Open stream from web
				speak("Fetching the script");
				mDestination = fileOrURLToOpen;
				HttpClient httpClient = new DefaultHttpClient();
				HttpContext localContext = new BasicHttpContext();
				HttpGet httpGet = null;
				try {
					httpGet = new HttpGet(mDestination);
				} catch (IllegalArgumentException e1) {
					e1.printStackTrace();
					speak("Sorry. The script could not be retrieved.");
				}
				if (null!=httpGet) {
					try {
						mHttpResponse = httpClient.execute(httpGet, localContext);
					} catch (ClientProtocolException e) {
						e.printStackTrace();
						speak("Sorry. The script could not be retrieved.");
					} catch (IOException e) {
						e.printStackTrace();
						speak("Sorry. The script could not be retrieved.");
					}
					String result = "";

					try {
						if(null!=mHttpResponse) {
							mBufferedReader = new BufferedReader(
									new InputStreamReader(mHttpResponse.getEntity().getContent())
							);
						}	
					} catch (IllegalStateException e) {
						e.printStackTrace();
						speak("Sorry. The script could not be retrieved.");
					} catch (IOException e) {
						e.printStackTrace();
						speak("Sorry. The script could not be retrieved.");
					}
					String line = null;
					try {
						while ((line = mBufferedReader.readLine()) != null){
							result += line + "\n";
						}
					} catch (IOException e) {
						e.printStackTrace();
						speak("Sorry. The script could not be retrieved.");
					}
//					print(result);

					// write to file on SD card
					FileOutputStream fOut;
					try {
						fOut = openFileOutput("fromWeb.html", MODE_WORLD_READABLE);
						OutputStreamWriter osw = new OutputStreamWriter(fOut);
						osw.write(result);
						osw.flush();
						osw.close();
					} catch (FileNotFoundException e) {
						e.printStackTrace();
						speak("Sorry. The script could not be retrieved.");
					} catch (IOException e) {
						e.printStackTrace();
						speak("Sorry. The script could not be retrieved.");
					}

					try {
						instream = openFileInput("fromWeb.html");
						if (0<fileOrURLToOpen.indexOf(".txt")) {
							ReadURL.readURL(this, instream, Constants.TXT);
						} else if (0<fileOrURLToOpen.indexOf("etherpad")) {
							ReadEtherpad.readEtherpad(this, instream, Constants.HTML_ETHERPAD);
						} else {
							ReadURL.readURL(this, instream, Constants.HTML);
						}
					} catch (FileNotFoundException e) {
						e.printStackTrace();
						speak("Sorry. The script could not be retrieved.");
					} 
				}
			} else {
				// Open stream from SD card
				if (-1==fileOrURLToOpen.indexOf("/sdcard/")) {
					mDestination = "/sdcard/WikiToSpeech/" + fileOrURLToOpen;
				} else {
					mDestination = fileOrURLToOpen;
				}
				print("mDestination to open: "+mDestination);
				try {
					instream = new FileInputStream(mDestination);
					ReadURL.readURL(this, instream, Constants.TXT);
				} catch (FileNotFoundException e) {
					// try adding .txt
					mDestination += ".txt";
					try {
						instream = new FileInputStream(mDestination);
						ReadURL.readURL(this, instream, Constants.TXT);
					} catch (FileNotFoundException e2) {
						e.printStackTrace();
						mStrings.clear();
						mStrings.add(fileOrURLToOpen + " could not be opened on SD card.");
						mStrings.add("Please check the file name and try again.");
						State.setSequence(MakeSequence.makeSequence(this, (String[]) mStrings.toArray(), false));
						State.clearQuestionsVisited();
						State.setOnQuestion(0);
					}
				}
			} 

			fileOrURLToOpen = null;
			State.setOnQuestion(0);
		} else {
			print("fileOrURLToOpen is null");
		}
	} // end of openFileOrURL()

	// --------------
	private class OpenFileOrURLAsyncTask extends AsyncTask<String, String, String> {
		/**
		 * Before jumping into background thread, start sliding in the
		 * {@link ProgressBar}. We'll only show it once the animation finishes.
		 */
		@Override
		protected void onPreExecute() {
			mLoadingLayout.setVisibility(View.VISIBLE);
		}

		/**
		 * Perform the background 
		 */
		@Override
		protected String doInBackground(String... args) {
			openFileOrURL();

			return null;
		}

		/**
		 * When finished, push the newly-found entry content into our
		 * {@link WebView} and hide the {@link ProgressBar}.
		 */
		@Override
		protected void onPostExecute(String parsedText) {
			mLoadingLayout.setVisibility(View.GONE);
			State.setOnQuestion(0);
			showQuestion();
		}
	}

	// --------------
	private class fetchZipFileAsyncTask extends AsyncTask<String, String, String> {
		/**
		 * Before jumping into background thread, start sliding in the
		 * {@link ProgressBar}. We'll only show it once the animation finishes.
		 */
		@Override
		protected void onPreExecute() {
			mLoadingLayout.setVisibility(View.VISIBLE);
		}

		/**
		 * Perform the background 
		 */
		@Override
		protected String doInBackground(String... args) {
			fetchZipFile();

			return null;
		}

		/**
		 * When finished, push the newly-found entry content into our
		 * {@link WebView} and hide the {@link ProgressBar}.
		 */
		@Override
		protected void onPostExecute(String parsedText) {
			mLoadingLayout.setVisibility(View.GONE);
			// Having fetched the zip file, start again going after it
			Intent i = new Intent(QuestionView.this, QuestionView.class);
			i.putExtra(Constants.EXTRA_INPUT_STRING, fileOrURLToOpen);
			i.putExtra(Constants.EXTRA_INPUT_TYPE, Constants.ZIP);
			i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
			startActivity(i);
		}
	}


} // end of TextToSpeechActivity